﻿using MiniJob.Worker.Jobs;
using System.Reflection;

namespace MiniJob.Worker.Runtime;

public class JobTypeInformation
{
    private JobTypeInformation()
    {
    }

    public string JobTypeName { get; private set; } = string.Empty;

    public required Type ImplementationType { get; set; }

    public bool IsAbstract { get; private set; }

    public static JobTypeInformation Get(Type jobType, string? jobTypeName)
    {
        if (!IsJob(jobType))
        {
            throw new ArgumentException($"The type '{jobType.FullName}' is not an Job. An job type must implement from '{typeof(Job).FullName}'.", nameof(jobType));
        }

        var jobAttribute = jobType.GetCustomAttribute<JobAttribute>();

        jobTypeName ??= jobAttribute?.TypeName ?? jobType.Name;

        return new JobTypeInformation()
        {
            JobTypeName = jobTypeName,
            ImplementationType = jobType,
            IsAbstract = jobType.GetTypeInfo().IsAbstract,
        };
    }

    public static bool IsJob(Type type)
    {
        return type.IsAssignableTo(typeof(Job));
    }

    public static Type[] GetJobInterfaces(Type type)
    {
        var list = new List<Type>(type.GetInterfaces().Where(t => typeof(Job).IsAssignableFrom(t)));
        list.RemoveAll(t => (GetNonJobParentType(t) != null));

        return [.. list];
    }

    public static Type? GetNonJobParentType(Type type)
    {
        var list = new List<Type>(type.GetInterfaces());

        if (list.RemoveAll(t => (t == typeof(Job))) == 0)
        {
            return type;
        }

        foreach (var t in list)
        {
            var nonJobParent = GetNonJobParentType(t);
            if (nonJobParent != null)
            {
                return nonJobParent;
            }
        }

        return null;
    }
}
